/* processtable.cc
	A class for holding processes related information in NACHOS
 */

#include "processtable.h"
#include "bitmap.h"
#include "synch.h"
#include "thread.h"


ProcessTable::ProcessTable() {
	processCount = 0;
	processesMap = new BitMap(MAX_PROCESSES);
	processesMapLock = new Lock("processesMapLock");
}

ProcessTable::~ProcessTable() {
	delete name;
	delete[] processesMap;
	delete processesMapLock;
}

Process*
ProcessTable::createProcess(char* debugName, AddrSpace* space) {
	int processID = -1;
	Process* process = NULL;

	if (space == NULL) {
		DEBUG('p', "[ERROR][createProcess] ProcessTable cannot create new Process due to NULL AddrSpace.\n");
		printf("[ERROR][createProcess] ProcessTable cannot create new Process due to NULL AddrSpace.\n");
		return process;
		//interrupt->Halt();
		//return;
	}

	//processesMapLock->Acquire();
	processID = processesMap->Find();
	
	if (processID == -1) {
		DEBUG('p', "[ERROR][createProcess] ProcessTable cannot create new Process due to max [%d] processes.\n", MAX_PROCESSES);
		printf("[ERROR][createProcess] ProcessTable cannot create new Process due to max [%d] processes.\n", MAX_PROCESSES);	
		//interrupt->Halt();
		//return;
	}
	else {
		process = new Process(debugName, processID, space);
		//process->processID = processID;
		//process->setAddrSpace(space);
		processes[processID] = process;
		processCount++;
		DEBUG('p', "[INFO][createProcess] ProcessTable created Process [%d].\n", processID);
		//printf("[INFO][createProcess] ProcessTable created Process [%d].\n", processID);
	}

	//processesMapLock->Release();

	return process;
}

int
ProcessTable::addProcess(Process* process) {
	int processID = -1;

	if (process->getAddrSpace() == NULL) {
		DEBUG('p', "[ERROR][addProcess] Process being added hasn't been allocated with AddrSpace.\n");
		//printf("[ERROR][addProcess] Process being added hasn't been allocated with AddrSpace.\n");
		return processID;
		//interrupt->Halt();
		//return;
	}

	//processesMapLock->Acquire();
	processID = processesMap->Find();

	if (processID == -1) {
		DEBUG('p', "[ERROR][addProcess] ProcessTable cannot create new Process due to max [%d] processes.\n", MAX_PROCESSES);
		//printf("[ERROR][addProcess] ProcessTable cannot create new Process due to max [%d] processes.\n", MAX_PROCESSES);
		//interrupt->Halt();
		//return;
	}
	else {
		DEBUG('p', "[INFO][addProcess] Process assigned with ID [%d] added to the ProcessTable.\n", processID);
		//printf("[INFO][addProcess] Process assigned with ID [%d] added to the ProcessTable.\n", processID);
		process->setProcessID(processID);
		processes[processID] = process;
		processCount++;
	}

	//processesMapLock->Release();

	return processID;
}

void
ProcessTable::removeProcess(int processID) {
	if (processID < 0 || processID >= MAX_PROCESSES) {
		DEBUG('p', "[ERROR][removeProcess] Process [%d] is invalid for removal for ProcessTable.\n", processID);
		//printf("[ERROR][removeProcess] Process [%d] is invalid for removal for ProcessTable.\n", processID);
		return;
		//interrupt->Halt();
		//return;
	}

	//processesMapLock->Acquire();
	
	if (!processesMap->Test(processID)) {
		DEBUG('p', "[ERROR][removeProcess] Process [%d] was not allocated for ProcessTable.\n", processID);
		//printf("[ERROR][removeProcess] Process [%d] was not allocated for ProcessTable.\n", processID);
		//interrupt->Halt();
		//return;
	}
	else {
		DEBUG('p',"[INFO][removeProcess] Process [%d] removed for ProcessTable.\n", processID);
		//printf("[INFO][removeProcess] Process [%d] removed for ProcessTable.\n", processID);
		//delete processes[processID];
		processes[processID] = NULL;
		processCount--;
		processesMap->Clear(processID);
	}

	//processesMapLock->Release();
}

int
ProcessTable::getProcessCount() {
	int theProcessCount;

	//processesMapLock->Acquire();
	if (processesMap->NumClear() != (MAX_PROCESSES-processCount)) {
		printf("[ERROR][getProcessCount] Number of Processes isn't maintained properly for ProcessTable.\n");
	}
	else {
		theProcessCount = processCount;
	}
	//processesMapLock->Release();

	return theProcessCount;
}

Process*
ProcessTable::getProcess(int processID) {
	Process* process = NULL;

	if (processID < 0 || processID >= MAX_PROCESSES) {
		DEBUG('p', "[ERROR][getProcess] Process [%d] is invalid for retrival for ProcessTable.\n", processID);
		//printf("[ERROR][getProcess] Process [%d] is invalid for retrival for ProcessTable.\n", processID);
		return NULL;
		//interrupt->Halt();
		//return;
	}

	//processesMapLock->Acquire();
	
	if (!processesMap->Test(processID)) {
		DEBUG('p', "[ERROR][getProcess] Process [%d] was not allocated for ProcessTable.\n", processID);
		//printf("[ERROR][getProcess] Process [%d] was not allocated for ProcessTable.\n", processID);
		//interrupt->Halt();
		//return;
	}
	else {
		DEBUG('p', "[INFO][getProcess] Process [%d] retrived for ProcessTable.\n", processID);
		//printf("[INFO][getProcess] Process [%d] retrived for ProcessTable.\n", processID);
		process = processes[processID];
	}

	//processesMapLock->Release();

	return process;
}
